const { src, dest, parallel, series, watch } = require('gulp')

const del = require('del')
const browserSync = require('browser-sync') // 提供热更新服务器模块

const loadPlugins = require('gulp-load-plugins') // 自动加载所有Gulp插件
const plugins = loadPlugins()
const bs = browserSync.create() // 创建一个开发服务器

// const plugins.sass = require('gulp-sass')
// const plugins.babel = require('gulp-babel') // 同时要手动安装@babel/code 和 @babel/preset-env
// const plugins.swig = require('gulp-swig')
// const plugins.imagemin = require('gulp-imagemin')

// 提前准备好的数据，文件转换时可以作为参数传递进去
const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

// 清楚文件的任务
const clean = () => {
  return del(['dist', 'temp'])
}

// 样式编译
const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' }) // 添加base属性，使文件按照原目录输出
    .pipe(plugins.sass({outputStyle: 'expanded'})) // outputStyle 样式展开方式编译
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true})) // 以流的方式往浏览器推送
}

// 脚本文件ES6编译
const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' }) // 添加base属性，使文件按照原目录输出
    .pipe(plugins.babel({presets: ['@babel/preset-env']})) // outputStyle 样式展开方式编译
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true}))
}

// 页面模板编译
const page = () => {
  return src('src/*.html', { base: 'src' }) // 如果其他子文件夹下也有html文件，可通过**\*匹配
    .pipe(plugins.swig({data}))
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true}))
}

// 图片和文字文件转换
const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin({}))
    .pipe(dest('dist'))
}
const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin({}))
    .pipe(dest('dist'))
}

// 其他不需要转换处理的文件，直接拷贝过去
const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}

// 开发服务器
const serve = () => {
  // watch监听对应路径的文件发生变化，就执行对应的任务，任务执行完毕，会导致dist文件发生变化，从而被服务器监听到完成热更新
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)

  // 构建优化
  // 开发阶段image font public的文件不必每次都进行压缩
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)

  // 开发阶段监听image font public的变化，执行reload就行了
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'], bs.reload)

  bs.init({ // 配置服务器的属性
    notify: false,
    port: 3000, // 端口号默认是3000
    open: true, // 自动打开浏览器
    // files: 'dist/**',// 服务器启动后，需要监听的文件,自动更新，也可以在每个任务最后执行reload去实现更新
    server: {
      baseDir: ['temp', 'src', 'public'], // 网页访问的根目录, 按顺序往下查找
      routes: { // 指定路径，会优先于baseDir的配置
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 文件引用处理(依赖文件和打包后的一些注释)
const useref = () => {
  // 处理转换后dist里面的文件
  return src('temp/*.html', {base: 'temp'})
    .pipe(plugins.useref({searchPath: ['temp', '.']}))
    // 压缩html js css, 需安装gulp-if插件，判断当前读取流是哪种文件
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true, // 处理空白字符
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
}
// 把同时执行的任务放一起
const compile = parallel(style, script, page)

// build之前先清楚dist文件夹
const build = series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra))

// 开发任务
const develop = series(compile, serve)

module.exports = {
  build,
  compile,
  serve,
  useref
}
